#include <iostream>
#include <vector>

//c
#include <unistd.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <arpa/inet.h>

int main() {
    /*
        select 监视的 fd 受限于 fd_set 的 __fd_mask 成员的大小
        poll 不受限, 其余跟 select 一模一样
        https://blog.csdn.net/weixin_43825537/article/details/90211331
    */

    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd == -1)
        return -1;

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERT_PORT);
    inet_pton(AF_INET, "0.0.0.0", &addr.sin_addr);

    if (bind(socketfd, (sockaddr*)(&addr), sizeof(sockaddr_in)) == -1)
        return -1;

    if (listen(socketfd, 4) == -1)
        return -1;

    std::vector<pollfd> fds;
    fds.push_back({
        socketfd,   //监听的fd
        POLLIN,     //监听的事件类型
        0           //返回结果由哪些监听事件触发
    });

    while (true) {
        int ret = poll(fds.data(), fds.size(), -1);

        if (ret <= 0)
            continue;

        //socketfd 有连接事件
        if (fds[0].revents & POLLIN) {
            sockaddr_in client;
            socklen_t len(sizeof(sockaddr_in));
            int clientfd = accept(socketfd, (sockaddr*)(&client), &len);

            if (clientfd <= 0)
                continue;

            fds.push_back({
                clientfd,
                POLLIN | POLLRDHUP, //可读 | 断开连接
                0
            });
        }

        //遍历 client
        for (auto it = fds.begin() + 1; it != fds.end();) {
            //client 输入
            if ((*it).revents & POLLIN) {
                char buf[MAXLINE + 1] = {0};
                if(read((*it).fd, buf, MAXLINE) == 0) {
                    close((*it).fd);
                    it = fds.erase(it);
                    continue;
                }
                std::cout << "client" << (*it).fd << ": " << buf << std::endl;
                write((*it).fd, buf, MAXLINE);  //echo
                it++;
            }
            //client 断开连接
            else if ((*it).revents & POLLRDHUP) {
                close((*it).fd);
                it = fds.erase(it);
            }

            else
                it++;
        }
    }
    

    return 0;
}